package cn.cas.mango.service.News2;

import cn.cas.mango.dto.param.GlobalParam;
import cn.cas.mango.dto.param.News;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldSort;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class GetJson2 {

  @Value("${elasticsearch.originalIndex}")
  private String index;

    private String dateField = "news_publicdate";


    @Autowired
    private ElasticsearchClient client;
    private SearchRequest getRequest(int from, String startDate, String endDate, int pageSize) {
        return SearchRequest.of(e -> e.index(index).from(from).size(pageSize)
                .sort(x->x.field(FieldSort.of(m->m.field(dateField).order(SortOrder.Asc))))
                .query(x -> x.bool(y -> y.filter(z -> z.range(m -> m.field(dateField)
                        .gte(JsonData.of(startDate)).lte(JsonData.of(endDate)))))).trackTotalHits(s->s.enabled(true)));
    }

    private SearchRequest getCount(String startDate, String endDate) {
        return SearchRequest.of(e -> e.index(index).size(0).query(x ->
                x.bool(y -> y.filter(z -> z.range(m -> m.field(dateField)
                        .gte(JsonData.of(startDate)).lte(JsonData.of(endDate)))))).trackTotalHits(s->s.enabled(true)));
    }

    private String getToday() {
      LocalDate localDate = LocalDate.now();
      String format = localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
      return format;
    }

    public List<List<News2>> main(GlobalParam globalParam) throws IOException {

        String startDate = globalParam.getStartDate() == null ? "1948-04-01": globalParam.getStartDate();
        String endDate = globalParam.getEndDate() == null ? getToday(): globalParam.getEndDate();

        int pageSize = globalParam.getPageSize();

        SearchRequest getCountRequest = getCount(startDate, endDate);
        log.info("get count from {} to {}: {}", startDate, endDate, getCountRequest);
        SearchResponse<News2> getCount = client.search(getCountRequest, News2.class);

        assert getCount.hits().total() != null;
        int count = (int)getCount.hits().total().value();
        int pages = (int)Math.ceil(count * 1.0 / pageSize);
        SearchResponse<News2> search;
        List<List<News2>> hits = new ArrayList<>();
        int all = 0;
        for (int i = 0; i < pages; i++) {
            SearchRequest request = getRequest(i * pageSize, startDate, endDate, pageSize);
            if (all == 0)
              log.info("get each of " + pageSize + " news queryStr: " + request);
            try {
                search = client.search(request, News2.class);
                SearchResponse<News2> finalSearch = search;
                List<News2> hitsTemp = new ArrayList<News2>() {{
                    List<Hit<News2>> hits1 = new ArrayList<>(finalSearch.hits().hits());
                    Map<String, Hit<News2>> map = new LinkedHashMap<String, Hit<News2>>(){{
                      for (Hit<News2> hit: hits1) {
                        assert hit.source() != null;
                        put(hit.source().getId(), hit);
                      }
                    }};
                    hits1.clear();
                    hits1.addAll(map.values());
                    for (Hit<News2> hit : hits1) {
                        add(hit.source());
                    }
                }};
                hits.add(hitsTemp);
                all += hitsTemp.size();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }


//            if ((i + 1) % 10 == 0)
//              log.info("finish {} jsons write", i + 1);
//            File file = new File(jsonPath + "/" + String.format("%010d", i + 1) + ".json");
//            all += hits.size();
//            mapper.writeValue(file, hits);
//            hits.clear();
        }
      log.info("write " + all + " news");
        return hits;
    }
}
